package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"gin/baidu"
	"gin/baidu/pcs"
	"gin/baidu/pcs/baidupcs"
	"gin/baidu/pcs/share/pcsconfig"
	"gin/common/types"
	Mysql "gin/database"
	"gin/model"
	"gin/response"
	"gin/validate"
	"github.com/gin-gonic/gin"
	uuid "github.com/satori/go.uuid"
	teamones_helper "github.com/teamones-open/go-helper"
	"strings"
	"time"
)

// 添加百度盘账户
func CreatePanUser(Data validate.AddPanUserData) (resData model.PanUser, err error) {
	var panUserModel model.PanUser
	panUserModel.BaiduName = Data.BaiduName
	panUserModel.TenantId = Data.TenantId
	panUserModel.UnionId = Data.UnionId

	if Data.ExpiryTime != "" {
		ExpiryTimeTimeStamp, _ := time.Parse("2006-01-02", Data.ExpiryTime)
		panUserModel.ExpiryTime = types.TstampTime(ExpiryTimeTimeStamp.Unix())
	}
	// 关联类型
	if Data.LinkType != "" {
		panUserModel.LinkType = Data.LinkType
	} else {
		panUserModel.LinkType = "user"
	}
	// 是否默认
	if Data.IsDefault != "" {
		panUserModel.IsDefault = Data.IsDefault
	} else {
		panUserModel.IsDefault = "no"
	}

	// 创建时间
	panUserModel.Created = types.TstampTime(time.Now().Unix())

	_, err = panUserModel.Insert()

	return panUserModel, err
}

// 更新百度盘账户信息、已经绑定授权的账户只能修改会员过期时间
func UpdatePanUser(Data validate.UpdatePanUserData) (resData model.PanUser, err error) {
	var panUserModel model.PanUser

	// 查询当前网盘账户是否已经被授权
	if Data.Id > 0 {
		panUserModel, err = panUserModel.FindById(Data.Id)
		if err != nil {
			return
		}
	}

	ExpiryTimeTimeStamp, _ := time.Parse("2006-01-02", Data.ExpiryTime)
	panUserModel.ExpiryTime = types.TstampTime(ExpiryTimeTimeStamp.Unix())

	if panUserModel.UkId <= 0 {
		// 修改用户信息
		panUserModel.BaiduName = Data.BaiduName
	}

	err = panUserModel.Update()

	return panUserModel, err
}

// 更新百度盘用户授权信息
func UpdatePanUserAuthorization(accessToken baidu.AccessToken, userInfo baidu.UserInfo) (err error) {
	// 通过 baidu_name 来查找是否存在用户，不存在则忽略（因为需要绑定租户信息）
	var panUserModel model.PanUser

	panUserModel, err = panUserModel.FindByBaiduName(userInfo.BaiduName)

	if err != nil {
		return
	}

	// 更新当前用户信息
	panUserModel.NetdiskName = userInfo.NetdiskName
	panUserModel.AvatarUrl = userInfo.AvatarUrl
	panUserModel.UkId = userInfo.UkId
	panUserModel.VipType = userInfo.VipType

	// 更新授权令牌信息
	panUserModel.AccessToken = accessToken.AccessToken
	panUserModel.RefreshToken = accessToken.RefreshToken
	panUserModel.Scope = accessToken.Scope
	panUserModel.ExpiresIn = time.Now().Unix() + accessToken.ExpiresIn
	panUserModel.IsAuthorize = 1

	err = panUserModel.Update()

	return
}

// 通过盘主键id来获取 Access Token
func GetAccessTokenById(Id uint64) (accessToken string, err error) {
	var panUserModel model.PanUser

	panUserModel, err = panUserModel.FindById(Id)

	if err != nil {
		return
	}

	if len(panUserModel.AccessToken) == 0 {
		err = errors.New("Access token not exist.")
		return
	}

	return panUserModel.AccessToken, err
}

// 更新所有即将过期用户令牌
func RefreshAllToken() (resData []model.PanUser, err error) {
	var panUserModel model.PanUser

	resData, err = panUserModel.FindExpiredInThreeDaysUser()

	if len(resData) == 0 {
		err = errors.New("There are no expired users.")
		return
	}

	// 循环更新token
	for _, baiduUser := range resData {
		newAccessToken, baiduErr := baidu.RefreshToken(baiduUser.RefreshToken)
		if baiduErr != nil {
			// 更新当前用户标记为异常
			baiduUser.FailedRefreshToken = 1
		} else {
			// 更新成功更新用户数据
			baiduUser.RefreshToken = newAccessToken.RefreshToken
			baiduUser.AccessToken = newAccessToken.AccessToken
			baiduUser.Scope = newAccessToken.Scope
			baiduUser.ExpiresIn = time.Now().Unix() + newAccessToken.ExpiresIn
		}

		// 更新数据
		err = baiduUser.Update()
	}

	return resData, err
}

// RecordUploadFile 添加上传的文件信息
func RecordUploadFile(Data validate.RecordPanFileParam) (resData model.PanFile, err error) {
	var panFileModel model.PanFile

	panFileModel.PanUserId = Data.PanUserId
	panFileModel.FsId = Data.FsId
	panFileModel.Md5 = Data.Md5
	panFileModel.ServerFilename = Data.ServerFilename
	panFileModel.Category = Data.Category
	panFileModel.Path = Data.Path
	panFileModel.Size = Data.Size
	panFileModel.IsDir = Data.IsDir
	panFileModel.Depth = len(strings.Split(Data.Path, "/"))
	panFileModel.FromShareId = Data.FromShareId

	panFileModel.Ctime = types.TstampTime(Data.Ctime)
	panFileModel.Mtime = types.TstampTime(Data.Mtime)

	// 创建时间
	panFileModel.Uuid = uuid.NewV4().String()

	_, err = panFileModel.Insert()

	return panFileModel, err
}

// 获取指定文件信息
func FindPanFileById(Id int64) (resData uint64, err error) {
	var panFileModel model.PanFile
	// 查询当前网盘账户是否已经被授权
	panFileModel, err = panFileModel.FindById(Id)

	if err != nil {
		return
	}

	if panFileModel.FsId == 0 {
		err = errors.New("Fsid not exist.")
		return
	}

	return panFileModel.FsId, err
}

// 查询panUser
func FindPanUserById(Id uint64) (model.PanUser, error) {
	res := model.PanUser{}
	err := model.FindById(&res, Id, nil)
	return res, err
}

// 查询文件列表
func SelectPanFile(param teamones_helper.SelectQueryParam) (int64, []model.PanFile, error) {

	rows := make([]model.PanFile, 0)
	resp := response.SelectResp{
		Total: 0,
		Rows:  &rows,
	}
	err := model.Select(&model.PanFile{}, &resp, param.Where, param.Limit, param.Offset, param.Fields, param.Order, nil)

	return resp.Total, rows, err
}

// 创建分享记录
func CreatePanShare(data *model.PanShare) error {
	err := model.Insert(&data)
	return err
}

// 获得分享链接
func GenerateShareUrl(v validate.GenerateShareUrl, sharePeriod int, oldShareId uint64) (ps model.PanShare, err error) {

	user, err := FindPanUserById(v.PanUserId)
	if err != nil {
		return
	}

	pcsConfig := pcs.GetBaiduPcsConfig()
	baiduUserInfo, err := pcsConfig.SwitchUser(&pcsconfig.BaiduBase{
		UID:  0,
		Name: user.BaiduName,
	})
	if err != nil {

		return
	}
	param := teamones_helper.SelectQueryParam{
		Fields: "*",
		Limit:  999,
		Offset: 0,
		Order:  "id DESC",
		Where: map[string]interface{}{
			"-eq": map[string]interface{}{
				"condition": "fs_id in (?)",
				"val":       v.FileFsIdList,
			},
			"-eq02": map[string]interface{}{
				"condition": "pan_user_id = ?",
				"val":       v.PanUserId,
			},
		},
	}
	_, panFileList, err := SelectPanFile(param)
	if err != nil {
		return
	}
	if len(panFileList) == 0 {

		err = errors.New(fmt.Sprintf("can`t found match file belongs to [%d]", v.PanUserId))
		return
	}
	PanFileIdList := make([]uint64, len(panFileList))
	sharePath := make([]string, len(panFileList))
	for key, file := range panFileList {
		sharePath[key] = file.Path
		PanFileIdList[key] = file.Id
	}

	shareOption := baidupcs.ShareOption{
		Password: teamones_helper.RandStringBytesMaskImprSrcUnsafe(4),
		Period:   sharePeriod,
	}

	shareInfo, err := baiduUserInfo.BaiduPCS().ShareSet(sharePath, &shareOption)

	if err != nil {
		return
	}

	PanFileId, _ := json.Marshal(PanFileIdList)

	ps.PanUserId = user.Id
	ps.PanFileId = PanFileId
	ps.Password = shareInfo.Pwd
	ps.ShareAt = types.TstampTime(time.Now().Unix())
	ps.ShareId = shareInfo.ShareID
	ps.Link = shareInfo.Link
	// 增加过期时间
	if sharePeriod == 0 {
		ps.ExpireAt = 0
	} else {
		ps.ExpireAt = time.Now().AddDate(0, 0, sharePeriod).Unix()
	}
	// 存在oldshareid
	if oldShareId > 0 {
		// 直接更新
		ps.Id = oldShareId
		Mysql.DB.Model(&model.PanShare{}).Updates(ps)
	} else {
		err = CreatePanShare(&ps)
		if err != nil {
			return
		}
	}
	return
}

// SelectPanShareFile 查询分享文件
func SelectPanShareFile(param teamones_helper.SelectQueryParam) (int64, []model.PanShare, error) {
	rows := make([]model.PanShare, 0)
	resp := response.SelectResp{
		Total: 0,
		Rows:  &rows,
	}
	err := model.Select(&model.PanShare{}, &resp, param.Where, param.Limit, param.Offset, param.Fields, param.Order, nil)

	return resp.Total, rows, err
}

// 查询panUser
func FindPanUserByUnionId(UnionId uint64) (model.PanUser, error) {
	res := model.PanUser{}
	db := Mysql.DB.Model(&res).Where("union_id = ?", UnionId).Last(&res)

	return res, db.Error
}

// PanFileManage 修改数据库pan file数据
func PanFileManage(v validate.PanFileManage, fRes baidu.FileManageRes) {
	switch v.Opera {
	case "delete":
		paths := make([]string, 0)
		for _, info := range fRes.Info {
			if info.Errno == 0 {
				paths = append(paths, info.Path)
			}
		}
		var panFiles []model.PanFile

		db := Mysql.DB.Model(&model.PanFile{}).Where("pan_user_id = ? AND path IN (?)", v.PanUserId, paths).Find(&panFiles)

		if db.Error != nil {
			return
		}
		for _, file := range panFiles {

			if file.IsDir == 1 {
				// 目录删除  使用like prefix 匹配
				_, _ = model.Delete(&model.PanFile{}, map[string]interface{}{
					"-eq": map[string]interface{}{
						"condition": "path LIKE ?",
						"val":       file.Path + "%",
					},
				})
			} else {
				// 文件 直接 id 精确删除
				_, _ = model.Delete(&model.PanFile{}, map[string]interface{}{
					"-eq": map[string]interface{}{
						"condition": "id = ?",
						"val":       file.Id,
					},
				})
			}
		}
		break
	case "copy":
		// 新增文件记录 todo
		//model.Insert()
		break
	case "mover":
		// 修改文件记录 todo
		break
	case "rename":
		// 修改文件记录
		var fileList []baidu.FileManageRenameFileListItem
		_ = json.Unmarshal([]byte(v.FileList), &fileList)

		for _, info := range fileList {

			pathPices := strings.Split(info.Path, "/")
			pathPices = pathPices[:len(pathPices)-1]
			pathPices = append(pathPices, info.Newname)

			newServerFilename := strings.Join(pathPices, "/")
			newPath := newServerFilename

			panFile := model.PanFile{}
			err := model.Find(&panFile, map[string]interface{}{
				"-eq": map[string]interface{}{
					"condition": "pan_user_id = ?",
					"val":       v.PanUserId,
				},
				"-eq3": map[string]interface{}{
					"condition": "path = ?",
					"val":       info.Path,
				},
			}, nil)
			if err != nil {
				println(err.Error())
				continue
			}
			if panFile.Id == 0 {
				continue
			}

			_, err = model.Update(&model.PanFile{}, map[string]interface{}{
				"-eq": map[string]interface{}{
					"condition": "id = ?",
					"val":       panFile.Id,
				}},
				map[string]interface{}{
					"path":            newPath,
					"server_filename": newServerFilename,
				})

			if err != nil {
				println(err)
			}
		}

		break
	}
}

// 获取指定分享信息
func FindPanShareById(Id uint64) (panShareModel model.PanShare, err error) {
	err = model.FindById(&panShareModel, Id, nil)
	return
}

// SelectPanFilesByShareId 通过share_id查询pan_file记录
func SelectPanFilesByShareId(shareId uint64, order string) (res []model.PanFile, err error) {
	db := Mysql.DB.Model(&model.PanFile{}).Where("JSON_CONTAINS((select pan_file_id from pan_share where id = ?), cast(pan_file.id as char ))", shareId).Order(order).Find(&res)
	if db.Error != nil {
		return res, db.Error
	}
	return
}

// SelectPanFilesByFromShareId 通过from_share_id 查询pan_file记录
func SelectPanFilesByFromShareId(shareId uint64, userId uint64, isDir int) (res []model.PanFile, err error) {
	db := Mysql.DB.Model(&model.PanFile{}).Where("from_share_id = ? and pan_user_id = ? and isdir = ?", shareId, userId, isDir).Find(&res)
	if db.Error != nil {
		return res, db.Error
	}
	return
}

func GetPanFileDownloadLinks(panFiles []model.PanFile, user model.PanUser) ([]model.PanFile, error) {
	FsIdList := make([]uint64, 0)

	fsl := len(panFiles)
	page := 1
	limit := 100
	start := 0
	end := 0
	//panFilesMap := map[uint64]*model.PanFile{}
	//for _, file := range panFiles {
	//	panFilesMap[file.FsId] = &file
	//}

	for {
		start = (page - 1) * limit
		end = start + limit - 1

		if end > fsl-1 {
			if page != 1 {
				// 如果超出范围 直接break跳出
				break
			} else {
				// 如果是第一页 并且超出范围 那么重置end为
				end = fsl - 1
			}
		}

		if start == 0 && end == 0 {
			FsIdList = []uint64{panFiles[0].FsId}
		} else {
			for _, panFile := range panFiles[start:end] {
				FsIdList = append(FsIdList, panFile.FsId)
			}
		}
		metaFileRes, err := baidu.GetFileMetaInfo(user.AccessToken, FsIdList, 0, 1, 0)

		if err != nil {
			return nil, err
		}
		fileMetasMap := make(map[uint64]baidu.FileMetaItem, len(metaFileRes.List))

		for _, fileMetaItem := range metaFileRes.List {
			fileMetasMap[fileMetaItem.FsId] = fileMetaItem
		}

		for index, panfile := range panFiles {
			if val, flag := fileMetasMap[panfile.FsId]; flag {
				panFiles[index].DownloadLink = fmt.Sprintf("%s&access_token=%s", val.Dlink, user.AccessToken)
			}
		}

		FsIdList = make([]uint64, 0)
		page += 1
	}
	return panFiles, nil

}

// 通过百度用户昵称获取账号
func FindPanUserByBaiduName(baiduName string) (res model.PanUser) {
	Mysql.DB.Where("baidu_name = ?", baiduName).Take(&res)
	return
}

// 更新百度盘用户授权信息
func UpdatePanUserAccessTokenInfo(accessToken baidu.NewAccessToken, user *model.PanUser) (model.PanUser, error) {
	// 通过 baidu_name 来查找是否存在用户，不存在则忽略（因为需要绑定租户信息）

	// 更新授权令牌信息
	db := Mysql.DB.Model(&user).Updates(map[string]interface{}{
		"AccessToken":  accessToken.AccessToken,
		"RefreshToken": accessToken.RefreshToken,
		"Scope":        accessToken.Scope,
		"ExpiresIn":    time.Now().Unix() + accessToken.ExpiresIn,
		"IsAuthorize":  1,
	})
	if db.Error != nil {
		return *user, db.Error
	}

	_ = model.FindById(&user, user.Id, nil)
	return *user, nil
}

// 从context获取panUser
func GetPanUserFromContext(c *gin.Context, key string) (panUser model.PanUser) {
	if val, ok := c.Get(key); ok && val != nil {
		panUser, _ = val.(model.PanUser)
	}
	return
}

// SelectPanUserByLinkData 通过关联数据查询网盘用户
func SelectPanUserByLinkData(unionId uint64, linkType string) (res []model.PanUser, err error) {
	db := Mysql.DB.Model(&model.PanUser{}).Where("union_id = ? AND link_type = ?", unionId, linkType).Find(&res)
	err = db.Error
	return
}

// SetDefaultUser 设置默认用户
func SetDefaultUser(panUserId uint64) (err error) {
	panUser, err := FindPanUserById(panUserId)
	if err != nil {
		return
	}
	Db := Mysql.DB.Model(&model.PanUser{}).Where("union_id = ? AND link_type = ? AND id <> ?", panUser.UnionId, panUser.LinkType, panUser.Id).Update("is_default", "no")
	if Db.Error != nil {
		err = Db.Error
		return
	}
	Db = Mysql.DB.Model(&model.PanUser{}).Where("id = ?", panUser.Id).Update("is_default", "yes")
	if Db.Error != nil {
		err = Db.Error
		return
	}
	return
}

// GetDefaultPanUser 查询默认网盘用户
func GetDefaultPanUser(unionId uint64, linkType string) (panUser model.PanUser, err error) {
	dbR := Mysql.DB.Model(&model.PanUser{}).Where("is_default = 'yes' AND link_type= ? AND union_id = ?", linkType, unionId).Take(&panUser)
	err = dbR.Error
	return
}
